
/* <<< COPYRIGHT START >>>
 * Copyright 2006-Present OxygenSoftwareLibrary.com
 * Licensed under the GNU Lesser General Public License.
 * http://www.gnu.org/licenses/lgpl.html
 * 
 * @author: Ugorji Dick-Nwoke
 * <<< COPYRIGHT END >>>
 */


package oxygen.jython;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Method;

import org.python.core.Py;
import org.python.core.PyObject;
import org.python.core.imp;
import org.python.util.InteractiveConsole;

/**
 * Uses overloaded methods, so that jython function wrappers 
 * can easily be written for them
 *
 * TBD: EZ syntax only applies for script mode???
 * If so, then we record line (else record line0)
 * Sample sequence of events:
 *   java -D
 */
public class OxyJythonInterpreter extends InteractiveConsole {
  //public static final String ENV_NAME = "oxyenv";
  //public static final String WL_ATTR_INTERP_NAME = "interp";
  public static final String INTERP_NAME = "interp";
  
  //This is really only valid if used within an interactive interpreter
  //or run in its own VM (not embedded)
  //We use imp.addModule, because that is what is used by the 
  //org.python.util.jython main method.
  private PrintWriter recpw;
  private boolean recording;
  private boolean ezSyntaxOn;
  private boolean enableClose;
  private boolean debug = false;
  private boolean showConvertedSyntax;
  
  private static String lsep = System.getProperty("line.separator");
  
  public void help() {
    String s = "You are using the Enhanced Jython Interpreter" + lsep + 
      "To toggle the easysyntax mode, use interp.easysyntax(1) or interp.easysyntax(0)" + lsep + 
      "To show the converted jython syntax, use interp.showconvertedsyntax(1) or interp.showconvertedsyntax(0)" + lsep + 
      "To record to a specific file, use interp.recordto(filename)";
    System.out.println(s);
  }

  public OxyJythonInterpreter() throws Exception {
    //use this, so that it can be used as is, for 
    //java -Dpython.console=OxyJythonInterpreter org.python.util.jython 
    this(imp.addModule("__main__").__dict__, null);
  }
  
  public OxyJythonInterpreter(PyObject _locals, String initclassname) throws Exception {
    super();
    System.out.println("Enhanced Jython Interpreter in use. Type interp.help() to see enhanced functions.");
    try {
      if(_locals != null) {
        setLocals(_locals);
      }
      set(INTERP_NAME, this);
      //set(ENV_NAME, new WLJythonEnvironment(this));
      if(initclassname != null) {
        Class c = Class.forName(initclassname);
        Method m = c.getMethod("init", new Class[]{InteractiveConsole.class});
        m.invoke(null, new Object[]{this});
      }
      recordto(System.out, false);
      //System.out.println("OxyJythonInterpreter called");
    } catch(Exception exc) {
      exc.printStackTrace();
      throw exc;
    }
  }
  
  public void recordto(File f) throws Exception {
    recordto(f.getCanonicalFile().getPath());
  }
  
  public void recordto(String fname) throws Exception {
    recordto(new FileOutputStream(fname, true), true);
  }
  
  public void recordto(OutputStream os) throws Exception {
    recordto(os, false);
  }
  
  public void recordto(OutputStream os, boolean doClose) throws Exception {
    if(isCurrentlyRecording()) {
      throw Py.RuntimeError("Recording in progress");
    }
    if(recpw != null && enableClose) {
      try {
        recpw.close();
      } catch(Exception exc) { }
    }
    if(os != null) {
      recpw = new PrintWriter(new OutputStreamWriter(os));
    }
    enableClose = doClose;
  }

  public boolean recording() {
    return recording;
  }
  
  public boolean recording(boolean b) {
    recording = b;
    return recording;
  }
  
  public boolean debug() {
    return debug;
  }
  
  public boolean debug(boolean b) {
    debug = b;
    return debug;
  }
  
  public boolean easysyntax() {
   return ezSyntaxOn;
  }
  
  public boolean easysyntax(boolean b) {
    ezSyntaxOn = b;
    return ezSyntaxOn;
  }
  
  public boolean showconvertedsyntax(boolean b) {
    showConvertedSyntax = b;
    return showConvertedSyntax;
  }
  
  public boolean showconvertedsyntax() {
    return showConvertedSyntax;
  }
  
  ////////////////////////////////
  // Actual over-riden methods below
  /////////////////////////////////


  public boolean push(String line) {
    //String line0 = line;
    line = getJythonSyntaxLine(line);
    boolean moreneeded = super.push(line);
    p1("Called push: returning: " + moreneeded + " for: " + line);
    if(!moreneeded) {
      doRecord(line); //line0
    }
    return moreneeded;
  }
  
  public static String getDefaultBanner() {
    return "Running the Oxy Jython Interpreter " + 
      InteractiveConsole.getDefaultBanner();
  }
  
  private boolean isCurrentlyRecording() {
    return (recording && (recpw != null));
  }
  
  private void doRecord(String s) {
    if(isCurrentlyRecording()) {
      recpw.println(s);
      recpw.flush();
    }
  }
  
  private String getJythonSyntaxLine(String line) {
    p1("orig line: " + line);
    if(ezSyntaxOn) {
      OxyJythonSyntaxHandler wljsh = new OxyJythonSyntaxHandler(line);
      p1("Trying EZ TO JYTHON ...");
      if(wljsh.convert()) {
        line = wljsh.getJythonSyntax();
        p1("EZ TO JYTHON: " + line);
        if(showConvertedSyntax) {
          System.out.println("EZ TO JYTHON: " + line);
        }
      }
    }
    return line;
  }
  
  private void p1(Object s) {
    if(debug) {
      if(s == null) {
        System.out.println(s);
      } else if(s instanceof Throwable) {
        ((Throwable)s).printStackTrace();
      } else {
        System.out.println(s);
      }
    }
  }
  
}
  
/*
  public boolean runsource(String source, String filename, String symbol) {
    String source0 = source;
    p1("source0: " + source0);
    if(ezSyntaxOn) {
      WLJythonSyntaxHandler wljsh = new WLJythonSyntaxHandler(source);
      p1("Trying EZ TO JYTHON ...");
      if(wljsh.convert()) {
        source = wljsh.getJythonSyntax();
        p1("EZ TO JYTHON: " + source);
      }
    }
    boolean moreneeded = super.runsource(source, filename, symbol);
    p1("Calling runsource: returning: " + moreneeded + " for: " + source);
    if(!moreneeded) {
      doRecord(source0);
    }
    return moreneeded;
  }

*/
